#include "stdafx.h"
/// Copyright 2012, Alex Averian, Yonan Research
/// Released under BSD Licence

#include "qdialog.h"
using namespace micro::dialog;


#include "qerror.h"
using namespace micro::utils;

#include "qwindowpos.h"
using namespace micro::gui;


INT_PTR QDialogBase::CreateModal( LPCTSTR templateName )
{
    return DialogBoxParam( GetModuleHandle( 0 ), templateName, ( m_parent ? m_parent->GetHandle() : nullptr ) , DialogProcedure, ( LPARAM )this );
}


INT_PTR QDialogBase::CreateModal( UINT resID )
{
    return CreateModal( MAKEINTRESOURCE( resID  ) );
}



void QDialogBase::CenterWindow( )
{
    HWND   hwnd = nullptr;//::GetActiveWindow();


    if ( hwnd == nullptr )
    {
        hwnd = ::GetDesktopWindow();
    }

    QRect rectToCenterOn;
    ::GetWindowRect( hwnd, rectToCenterOn );


    /*
    else
    {
    	rectToCenterOn = pWndToCenterOn->GetWindowRect();
    }*/

    // Get this window's area
    QRect rectSubDialog =  GetWindowRect();

    // Now rectWndToCenterOn contains the screen rectangle of the window
    // pointed to by pWndToCenterOn.  Next, we apply the same centering
    // algorithm as does CenterWindow()

    // find the upper left of where we should center to

    int xLeft = ( rectToCenterOn.Width()   -   rectSubDialog.Width() ) / 2;

    int yTop = ( rectToCenterOn.Height() - rectSubDialog.Height() ) / 2;

    // Move the window to the correct coordinates with SetWindowPos()
    SetWindowPos( nullptr, xLeft, yTop, 0, 0,
                  SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
}


bool QDialogBase::OnButtonClicked( int buttonID, HWND buttonHWND )
{
    switch( buttonID )
    {
        case IDOK:
            OnOK();
            break;
        case IDCANCEL:
            OnCancel();
            break;
        case IDHELP:
            OnHelp();
            break;

    }
    return true;
}
bool QDialogBase::OnCommand( WPARAM wParam, LPARAM lParam )
{

    int code   = HIWORD( wParam );
    int itemID = LOWORD( wParam );
    //LPARAM lParam;

    if ( code == BN_CLICKED )
        return OnButtonClicked( itemID, ( HWND )lParam );

    return false;
}
bool QDialogBase::OnMessage( UINT message, WPARAM wParam, LPARAM lParam )
{

    LRESULT lResult = 0;

    switch ( message )
    {
        case WM_INITDIALOG:
            return OnInit();

        case WM_COMMAND:
            return OnCommand( wParam, lParam );

        case WM_CLOSE:
            return OnClose();

        case WM_CTLCOLORDLG:
            return false;


        case WM_NOTIFY:
            return OnNotify( wParam, ( LPNMHDR ) lParam,  lResult );

        case WM_HELP:
            return OnHelp( ( LPHELPINFO )lParam );

        case WM_TIMER:
            return OnTimer( wParam  );


        default:
            return false;
    }
}



INT_PTR APIENTRY QDialogBase::DialogProcedure( HWND dialogHWND, UINT message,  WPARAM wParam, LPARAM lParam )
{
    
    if ( message == WM_INITDIALOG )
		::SetWindowLongPtr(dialogHWND, GWLP_USERDATA, lParam );

    QDialog *dialog = reinterpret_cast< QDialog * > ( ::GetWindowLongPtr(dialogHWND, GWLP_USERDATA) );

    if ( dialog == nullptr )  return FALSE;

    if ( message == WM_INITDIALOG )
        dialog->Attach( dialogHWND );

    try
    {


        bool bo =  dialog->OnMessage( message, wParam, lParam );


        if( bo )  return 1;


    }
    catch( ... )
    {
        QError e ;
        e.PrintMessage();
    }


    return  0;
}



bool QModelessDialog::DoModeless()
{
    if( CreateModelessDialog() )
    {
        CenterWindow();
        Show();
        UpdateWindow();
        return true;
    }
    return false;
}


//create but not show
bool QModelessDialog::CreateModelessDialog()
{
    LPCTSTR    res = MAKEINTRESOURCE( m_id  );

    HINSTANCE hInst = GetModuleHandle( 0 );
    ASSERT( hInst );

    HRSRC hResource = ::FindResource( hInst, res, RT_DIALOG );
    ASSERT( hResource );

    HGLOBAL hTemplate = LoadResource( hInst, hResource );
    ASSERT( hTemplate );

    LPCDLGTEMPLATE lpDialogTemplate = ( LPCDLGTEMPLATE )LockResource( hTemplate );
    ASSERT( lpDialogTemplate );

    _window = ::CreateDialogIndirect( hInst, lpDialogTemplate, ( m_parent ? m_parent->GetHandle() : nullptr ), DialogProcedure );

    ASSERT( _window );
    SendMessage( WM_INITDIALOG, 0, ( LPARAM ) this );

    UnlockResource( hTemplate );
    FreeResource( hTemplate );


    return true;
}




//// RESIZEDIALOG ///////////////////////////////////////////////////////////////////////////////////////////////

// to enable a dialog to be resizable do the following after including this header:
//
// 1) in your class declare
//      private:
//          static const ANCHOR c_rgAnchors[5];
//          RECT _rgAnchorOffsets[ARRAYSIZE(c_rgAnchors)];
//
// 2) declare an entry in this table for every control in your dialog, for example
//
//      const ANCHOR CShellQueryInspectorApp::c_rgAnchors[] =
//      {
//          { IDC_QUERY,        AF_LEFT | AF_BOTTOM },
//          { IDC_OPEN_ITEM,    AF_LEFT | AF_BOTTOM },
//          { IDC_PICK,         AF_LEFT | AF_BOTTOM },
//          { IDC_STATIC,       AF_LEFT | AF_RIGHT | AF_TOP | AF_BOTTOM },
//          { IDC_LISTVIEW,     AF_LEFT | AF_RIGHT | AF_TOP | AF_BOTTOM },
//      };
//
// 3) in your DialogProc add
//      case WM_SIZE:
//          OnSize(_hdlg, c_rgAnchors, ARRAYSIZE(c_rgAnchors), _rgAnchorOffsets);
//          break;
//
//      case WM_INITDIALOG:
//          InitResizeData(_hdlg, c_rgAnchors, ARRAYSIZE(c_rgAnchors), _rgAnchorOffsets);
//          break;
//


void QResizeDialog::GetWindowRectInClient( UINT id, RECT *prect )
{
    HWND hwnd = GetItem( id );
    GetWindowRectInClient( hwnd, prect );
}

void QResizeDialog::GetWindowRectInClient( HWND hwnd, RECT *prect )
{
    ::GetWindowRect( hwnd, prect );
    ::MapWindowPoints( GetDesktopWindow(), _window, ( POINT* )prect, 2 );
}

void  QResizeDialog::InitResizeData( )
{
    // record anchor information
    QRect  rcClient  =	GetClientRect();
    int nr = m_anchors.GetSize();

    for ( int iAnchor = 0; iAnchor < nr; iAnchor++ )
    {
        GetWindowRectInClient(  m_anchors[iAnchor].idControl , &m_anchors[iAnchor].rect );

        switch ( m_anchors[iAnchor].aff & AF_LEFT_AND_RIGHT )
        {
            case AF_LEFT_AND_RIGHT:
                m_anchors[iAnchor].rect.left -= rcClient.left;    // offset
                m_anchors[iAnchor].rect.right -= rcClient.right;  // offset
                break;

            case AF_RIGHT:
                m_anchors[iAnchor].rect.left = m_anchors[iAnchor].rect.right - m_anchors[iAnchor].rect.left;  // width
                m_anchors[iAnchor].rect.right -= rcClient.right;  // offset
                break;
        }

        switch ( m_anchors[iAnchor].aff & AF_TOP_AND_BOTTOM )
        {
            case AF_TOP_AND_BOTTOM:
                m_anchors[iAnchor].rect.top -= rcClient.top;       // offset
                m_anchors[iAnchor].rect.bottom -= rcClient.bottom; // offset
                break;

            case AF_BOTTOM:
                m_anchors[iAnchor].rect.top = m_anchors[iAnchor].rect.bottom - m_anchors[iAnchor].rect.top;   // height
                m_anchors[iAnchor].rect.bottom -= rcClient.bottom; // offset
                break;
        }
    }
}

void QResizeDialog::ReSizeControls( )
{
    int nr = m_anchors.GetSize();

    //QWindowPos pos(nr);

    HDWP hdwp = ::BeginDeferWindowPos( nr );

    if ( hdwp )
    {
        QRect  rcClient = GetClientRect();


        for ( int iAnchor = 0; iAnchor < nr; iAnchor++ )
        {
            const HWND hwndControl = GetItem( m_anchors[iAnchor].idControl );

            QRect rcNewPos;
            GetWindowRectInClient( hwndControl, &rcNewPos );
            const ANCHOR &anchor = m_anchors[iAnchor];

            switch ( anchor.aff & AF_LEFT_AND_RIGHT )
            {
                case AF_RIGHT:
                    rcNewPos.right = rcClient.right + m_anchors[iAnchor].rect.right;
                    rcNewPos.left = rcNewPos.right - m_anchors[iAnchor].rect.left; // rgAnchorOffsets[iAnchor].left contains the width of the control
                    break;
                case AF_LEFT_AND_RIGHT:
                    rcNewPos.right = rcClient.right + m_anchors[iAnchor].rect.right;
                    break;
            }

            switch ( anchor.aff & AF_TOP_AND_BOTTOM )
            {
                case AF_BOTTOM:
                    rcNewPos.bottom = rcClient.bottom + m_anchors[iAnchor].rect.bottom;
                    rcNewPos.top = rcNewPos.bottom - m_anchors[iAnchor].rect.top; // rgAnchorOffsets[iAnchor].top contains the height of the control
                    break;
                case AF_TOP_AND_BOTTOM:
                    rcNewPos.bottom = rcClient.bottom + m_anchors[iAnchor].rect.bottom;
                    break;
            }

            ::MoveWindow( hwndControl, rcNewPos.left, rcNewPos.top, rcNewPos.right - rcNewPos.left,  rcNewPos.bottom - rcNewPos.top, TRUE );

            ::DeferWindowPos( hdwp, hwndControl, 0, rcNewPos.left, rcNewPos.top, rcNewPos.right - rcNewPos.left,  rcNewPos.bottom - rcNewPos.top, SWP_NOZORDER | SWP_NOACTIVATE );
        }
        ::EndDeferWindowPos( hdwp );
    }
}